home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Libraries / TransDisplay / TransDisplay.c < prev    next >
Text File  |  1994-02-23  |  29KB  |  1,213 lines

  1. /*
  2.  * Use SetScrollValue() in preference to SetCtlValue() when setting scroll
  3.  */
  4.  
  5. /*
  6.  * TransDisplay version 3.05 - TransSkel plug-in module supporting
  7.  * an arbitrary number of generic display windows with memory.
  8.  *
  9.  * TransSkel and TransDisplay are public domain.  For more information,
  10.  * contact:
  11.  *
  12.  *             Paul DuBois
  13.  *             Wisconsin Regional Primate Research Center
  14.  *             1220 Capitol Court
  15.  *             Madison, WI  53715-1299  USA
  16.  *
  17.  * Internet:    dubois@primate.wisc.edu
  18.  *
  19.  *
  20.  * This version of TransDisplay is written for THINK C 6.0.
  21.  * THINK C is a trademark of:
  22.  *
  23.  *             Symantec Corporation
  24.  *             10201 Torre Avenue
  25.  *             Cupertino, CA 95014  USA
  26.  *
  27.  * History
  28.  * 08/25/86    Genesis.  Beta version.
  29.  *
  30.  * 09/15/86 Release 1.0
  31.  * Changed to allow arbitrary number of windows.
  32.  *
  33.  * 01/17/87    Release 1.01
  34.  * The window type when a new window is created with NewDWindow is
  35.  * documentProc+8 now, so that the window will have a zoom box on a
  36.  * machine with 128K ROMS.
  37.  *
  38.  * 01/29/89    Release 2.0
  39.  * Converted to work with TransSkel 2.0.  Display window creation routines
  40.  * now check whether window and window handler creation succeeded and
  41.  * return nil if not.  2-byte and 4-byte integer types are typedef'ed to
  42.  * Integer and LongInt to ease porting.
  43.  *
  44.  * 24 Dec 90 Release 3.01
  45.  * - Started converting to work with TransSkel 3.
  46.  * - Began adding prototypes.
  47.  * 01 Jan 91
  48.  * - Took out the Macintosh header file #includes.  <MacHeaders> is assumed
  49.  * to be turned on so that it's not necessary.
  50.  * 06 Jun 92
  51.  * - Fixed GetDWindowTE() bug.  Was returning nil under multiwindow
  52.  * compilation.
  53.  *
  54.  * 05 Jun 93 Release 3.02
  55.  * - Conversion for THINK C 6.0.
  56.  *
  57.  * 07 Jun 93 Release 3.03
  58.  * - Took out all the stuff to allow compiling to handle only a single
  59.  * display window.  The savings in bytes of object code is no longer worth
  60.  * the extra source code complexity.  It's also unnecessary because I no longer
  61.  * maintain a window list, since I ...
  62.  * - Reimplemented linked list holding display window data using TransSkel's
  63.  * window property functions (new in TS 3.00).  The property type is
  64.  * skelWPropDisplayWind, and the data value is a handle to the window data
  65.  * structure.
  66.  * - Took out all the "register" declarations.  The compiler's smart enough
  67.  * now that they don't make any difference, so they're just clutter.
  68.  * 05 Jul 93
  69.  * - Fixed Activate() and Update() so that when a window goes inactive,
  70.  * the scroll bar is hidden (and only the frame drawn).  Previously, the
  71.  * scroll bar was just made inactive, which doesn't quite conform to the user
  72.  * interface guidelines.
  73.  * 17 Oct 93
  74.  * - Added DisplayOSType() function.
  75.  * 25 Nov 93
  76.  * - Tests to check whether a window is the active window now test w->hilited
  77.  * rather than FrontWindow(), since the front window of a suspended application
  78.  * isn't active.
  79.  * - Changed GetDWindow() so the WindowPtr is returned as the function value
  80.  * rather than in the argument.
  81.  * 21 Dec 93
  82.  * - Use color grafports when available.
  83.  * 04 Jan 94
  84.  * - Undid Integer/LongInt type stuff back to short/long.
  85.  *
  86.  * 18 Jan 94 Release 3.04
  87.  * - DisplayInt() and DisplayHexInt() are problematic since the THINK C can
  88.  * treat int's as either 2 or 4 bytes.  Added new routines DisplayShort()
  89.  * and DisplayHexShort() which are unambiguous for 2 byte integers.
  90.  * DisplayInt() and DisplayHexInt() are now deprecated and will disappear
  91.  * in the future.
  92.  * - New routine DisplayCString() for C-style strings.
  93.  * 19 Jan 94
  94.  * - Window creation routines do better checks for allocation failures.
  95.  * - Much rewriting to eliminate many global variables.  No more SyncGlobals().
  96.  *
  97.  * 20 Feb 94 Release 3.05
  98.  * - Updated for TransSkel 3.11.
  99.  * - Converted interface to be Pascal-compatible.
  100.  */
  101.  
  102.  
  103. # include    "TransSkel.h"
  104.  
  105. # include    "TransDisplay.h"
  106.  
  107.  
  108. # define    normalHilite    0
  109. # define    dimHilite        255
  110.  
  111. # define    WindowIsActive(w)    ((WindowPeek) (w))->hilited
  112.  
  113.  
  114. /*
  115.  * New(TypeName) returns handle to new object, for any TypeName.
  116.  * If there is insufficient memory, the result is nil.
  117.  */
  118.  
  119. # define    New(type)    (type **) NewHandle ((Size) sizeof (type))
  120.  
  121.  
  122. /*
  123.  * Default values for display window characteristics.  Used when
  124.  * new display windows are created.
  125.  */
  126.  
  127. static short    d_font = monaco;        /* default font              */
  128. static short    d_size = 9;                /* default pointsize         */
  129. static short    d_wrap = 0;                /* default word wrap (on)    */
  130. static short    d_just = teJustLeft;    /* default justification     */
  131. static long    d_maxText = 30000L;        /* default max text allowed  */
  132. static long    d_flushAmt = 25000L;    /* default autoflush amount  */
  133. static TDispActivateProcPtr        d_activate = (TDispActivateProcPtr) nil;    /* default notification proc */
  134.  
  135.  
  136. /*
  137.  * Lowest allowable values for autoflush characteristics
  138.  */
  139.  
  140. # define    d_loMaxText        (100L)
  141. # define    d_loFlushAmt    (100L)
  142.  
  143.  
  144. /*
  145.  * Display window document record.  A handle to a window's document
  146.  * record is stored in the window's property list.
  147.  */
  148.  
  149. typedef struct DocRecord DocRecord, *DocPtr, **DocHandle;
  150.  
  151. struct DocRecord
  152. {
  153.     WindowPtr                dWind;        /* display window         */
  154.     TEHandle                dTE;        /* window text            */
  155.     ControlHandle            dScroll;    /* window scroll bar      */
  156.     TDispActivateProcPtr    dActivate;    /* notification procedure */
  157.     long                    dMaxText;    /* max text length        */
  158.     long                    dFlushAmt;    /* amount to autoflush    */
  159. };
  160.  
  161.  
  162. /*
  163.  * Macros for accessing parts of a document record, given a document
  164.  * handle.
  165.  */
  166.  
  167. # define    DocWind(doc)            ((**doc).dWind)
  168. # define    DocTE(doc)                ((**doc).dTE)
  169. # define    DocScroll(doc)            ((**doc).dScroll)
  170. # define    DocActivateProc(doc)    ((**doc).dActivate)
  171. # define    DocMaxText(doc)            ((**doc).dMaxText)
  172. # define    DocFlushAmt(doc)        ((**doc).dFlushAmt)
  173.  
  174.  
  175. /*
  176.  * curDispWind is the current output window.
  177.  * If curDispWind = nil, output is currently turned off.
  178.  */
  179.  
  180. static WindowPtr    curDispWind = nil;
  181.  
  182.  
  183.  
  184. /* -------------------------------------------------------------------- */
  185. /*                Miscellaneous Internal (private) Routines                */
  186. /* -------------------------------------------------------------------- */
  187.  
  188.  
  189. /*
  190.  * Draw grow box of dispWind in lower right hand corner
  191.  */
  192.  
  193.  
  194. static void
  195. DrawGrowBox (WindowPtr w)
  196. {
  197. RgnHandle    oldClip;
  198. Rect        r;
  199.  
  200.     r = w->portRect;
  201.     r.left = r.right - 15;        /* draw only in corner */
  202.     r.top = r.bottom - 15;
  203.     oldClip = NewRgn ();
  204.     GetClip (oldClip);
  205.     ClipRect (&r);
  206.     DrawGrowIcon (w);
  207.     SetClip (oldClip);
  208.     DisposeRgn (oldClip);
  209. }
  210.  
  211.  
  212.  
  213. /* -------------------------------------------------------------------- */
  214. /*            Lowest-level Internal (Private) Display Window Routines        */
  215. /* -------------------------------------------------------------------- */
  216.  
  217.  
  218. /*
  219.  * Get document handle associated with display window.
  220.  * Return nil if window isn't a known display window.
  221.  */
  222.  
  223. static DocHandle
  224. WindDocHandle (WindowPtr w)
  225. {
  226. SkelWindPropHandle    ph;
  227. DocHandle    doc = (DocHandle) nil;
  228.  
  229.     if (w != (WindowPtr) nil)
  230.     {
  231.         ph = SkelGetWindProp (w, skelWPropDisplayWind);
  232.         if (ph != (SkelWindPropHandle) nil)
  233.             doc = (DocHandle) (**ph).skelWPropData;
  234.     }
  235.     return (doc);
  236. }
  237.  
  238.  
  239. /*
  240.  * Calculate the dimensions of the editing rectangle for
  241.  * a window (which is assumed to be
  242.  * the current port).  (The viewRect and destRect are the
  243.  * same size.)  Assumes the port, text font and text size are all
  244.  * set properly.  The viewRect is sized so that an integral
  245.  * number of lines can be displayed in it, i.e., so that a
  246.  * partial line never shows at the bottom.
  247.  */
  248.  
  249. static void
  250. CalcEditRect (WindowPtr w, Rect *r)
  251. {
  252. FontInfo    f;
  253. short        lineHeight;
  254.  
  255.     GetFontInfo (&f);
  256.     lineHeight = f.ascent + f.descent + f.leading;
  257.     *r = w->portRect;
  258.     r->left += 4;
  259.     r->right -= 17;            /* leave room for scroll bar + 2 */
  260.     r->top += 2;
  261.     r->bottom = r->top + ((r->bottom - r->top - 2) / lineHeight) * lineHeight;
  262. }
  263.  
  264.  
  265. /*
  266.  * Calculate the dimensions of the scroll bar rectangle for a
  267.  * window.  Make sure that the edges overlap the window frame and
  268.  * the grow box.
  269.  */
  270.  
  271. static void
  272. CalcScrollRect (WindowPtr w, Rect *r)
  273. {
  274.     *r = w->portRect;
  275.     ++r->right;
  276.     --r->top;
  277.     r->left = r->right - 16;
  278.     r->bottom -= 14;
  279. }
  280.  
  281.  
  282. /*
  283.  * Calculate the number of lines currently scrolled off
  284.  * the top of an edit record.
  285.  */
  286.  
  287. static short
  288. LinesOffTop (TEHandle hTE)
  289. {
  290.     return (((**hTE).viewRect.top - (**hTE).destRect.top) / (**hTE).lineHeight);
  291. }
  292.  
  293.  
  294. /*
  295.  * Highlight the scroll bar properly.  This means that it's not
  296.  * made active if the window itself isn't active, even if
  297.  * there's enough text to fill the window.
  298.  */
  299.  
  300. static void
  301. HiliteScroll (DocHandle doc)
  302. {
  303. WindowPtr    w;
  304. ControlHandle    scroll;
  305. short    hilite;
  306.  
  307.     w = DocWind (doc);
  308.     scroll = DocScroll (doc);
  309.     hilite = (WindowIsActive (w) && GetCtlMax (scroll) > 0
  310.                 ? normalHilite : dimHilite);
  311.     HiliteControl (scroll, hilite);
  312. }
  313.  
  314.  
  315. /*
  316.  * Set scroll bar current value (but only if it's different than
  317.  * the current value, to avoid needless flashing).
  318.  */
  319.  
  320. static void
  321. SetScrollValue (ControlHandle scroll, short value)
  322. {
  323.     if (GetCtlValue (scroll) != value)
  324.         SetCtlValue (scroll, value);
  325. }
  326.  
  327.  
  328. /*
  329.  * Scroll to the correct position.  lDelta is the
  330.  * amount to CHANGE the current scroll setting by.
  331.  * Positive scrolls the text up, negative down.
  332.  */
  333.  
  334. static void
  335. ScrollText (DocHandle doc, short lDelta)
  336. {
  337. ControlHandle    scroll;
  338. TEHandle    hTE;
  339. short    topVisLine;
  340. short    newTopVisLine;
  341.  
  342.     scroll = DocScroll (doc);
  343.     hTE = DocTE (doc);
  344.  
  345.     topVisLine = LinesOffTop (hTE);
  346.     newTopVisLine = topVisLine + lDelta;
  347.     if (newTopVisLine < 0)                    /* clip to range */
  348.         newTopVisLine = 0;
  349.     if (newTopVisLine > GetCtlMax (scroll))
  350.         newTopVisLine = GetCtlMax (scroll);
  351.     SetScrollValue (scroll, newTopVisLine);
  352.     TEScroll (0, (topVisLine - newTopVisLine ) * (**hTE).lineHeight, hTE);
  353. }
  354.  
  355.  
  356. /*
  357.  * Filter proc for tracking mousedown in scroll bar.
  358.  *
  359.  * Scroll by one line if the mouse is in an arrow.  Scroll by a half
  360.  * window's worth of lines if the mouse is in a page region.
  361.  *
  362.  * TrackScroll() uses scrollDoc and scrollPart, which must be set in
  363.  * Mouse() before calling TrackControl(), which calls TrackScroll().
  364.  * scrollPart is the original part code in which the mousedown occurred.
  365.  */
  366.  
  367. static DocHandle    scrollDoc;
  368. static short        scrollPart;
  369.  
  370. static pascal void
  371. TrackScroll (ControlHandle theScroll, short partCode)
  372. {
  373. TEHandle    hTE;
  374. short    lDelta;
  375. short    halfPage;
  376.  
  377.     hTE = DocTE (scrollDoc);
  378.     if (partCode == scrollPart)            /* still in same part? */
  379.     {
  380.         halfPage = (((**hTE).viewRect.bottom - (**hTE).viewRect.top)
  381.                         / (**hTE).lineHeight) / 2;
  382.         if (halfPage == 0)
  383.             ++halfPage;
  384.         switch (partCode)
  385.         {
  386.             case inUpButton: lDelta = -1; break;
  387.             case inDownButton: lDelta = 1; break;
  388.             case inPageUp: lDelta = -halfPage; break;
  389.             case inPageDown: lDelta = halfPage; break;
  390.         }
  391.         ScrollText (scrollDoc, lDelta);
  392.     }
  393. }
  394.  
  395.  
  396. /*
  397.  * Overhaul the entire display.  This is called after catastrophic
  398.  * events, such as resizing the window, or changes to the word
  399.  * wrap style.  It makes sure the view and destination rectangles
  400.  * are sized properly, and that the bottom line of text never
  401.  * scrolls up past the bottom line of the window (if there's
  402.  * enough to fill the window), and that the scroll bar max and
  403.  * current values are set properly.
  404.  *
  405.  * Resizing the dest rect just means resetting the right edge
  406.  * (the top is NOT reset), since text might be scrolled off the
  407.  * top (i.e., destRect.top != 0).
  408.  */
  409.  
  410. static void
  411. OverhaulDisplay (DocHandle doc)
  412. {
  413. WindowPtr    w;
  414. TEHandle    hTE;
  415. ControlHandle    scroll;
  416. Rect    r;
  417. short    nLines;            /* # of lines in TERec */
  418. short    visLines;        /* # of lines displayable in window */
  419. short    topLines;        /* # of lines currently scrolled off top */
  420. short    scrollLines;    /* # of lines to scroll down */
  421. short    lHeight;
  422.  
  423.     w = DocWind (doc);
  424.     hTE = DocTE (doc);
  425.     scroll = DocScroll (doc);
  426.     CalcEditRect (w, &r);
  427.     (**hTE).destRect.right = r.right;
  428.     (**hTE).viewRect = r;
  429.     TECalText (hTE);        /* recalc line starts */
  430.     lHeight = (**hTE).lineHeight;
  431.     nLines = (**hTE).nLines;
  432.     visLines = (r.bottom - r.top) / lHeight;
  433.     topLines = LinesOffTop (hTE);
  434.  
  435.     /*
  436.      * If the text doesn't fill the window (visLines > nLines - topLines),
  437.      * pull the text down if possible (if topLines > 0).  Make sure not
  438.      * to try to scroll down by more lines than are hidden off the top.
  439.      */
  440.     scrollLines = visLines - (nLines - topLines);
  441.     if (scrollLines > 0 && topLines > 0)
  442.     {
  443.         if (scrollLines > topLines)
  444.             scrollLines = topLines;
  445.         TEScroll (0, scrollLines * lHeight, hTE);
  446.         topLines -= scrollLines;
  447.     }
  448.     TEUpdate (&r, hTE);
  449.  
  450.     SetCtlMax (scroll, nLines - visLines < 0 ? 0 : nLines - visLines);
  451.     SetCtlValue (scroll, topLines);
  452.     HiliteScroll (doc);
  453. }
  454.  
  455.  
  456. /* ---------------------------------------------------------------- */
  457. /*                        Window Handler Routines                        */
  458. /* ---------------------------------------------------------------- */
  459.  
  460.  
  461. /*
  462.  * Handle mouse clicks in window
  463.  */
  464.  
  465. static pascal void
  466. Mouse (Point thePt, long t, short mods)
  467. {
  468. WindowPtr    w;
  469. DocHandle    doc;
  470. ControlHandle    scroll;
  471. short    thePart;
  472. short    oldCtlValue;
  473.  
  474.     GetPort (&w);
  475.     doc = WindDocHandle (w);
  476.     scroll = DocScroll (doc);
  477.  
  478.     if ((thePart = TestControl (scroll, thePt)) == inThumb)
  479.     {
  480.         oldCtlValue = GetCtlValue (scroll);
  481.         if (TrackControl (scroll, thePt, nil) == inThumb)
  482.             ScrollText (doc, GetCtlValue (scroll) - oldCtlValue);
  483.     }
  484.     else if (thePart != 0)
  485.     {
  486.         scrollDoc = doc;        /* set globals for TrackScroll */
  487.         scrollPart = thePart;
  488.         (void) TrackControl (scroll, thePt, &TrackScroll);
  489.     }
  490. }
  491.  
  492.  
  493. /*
  494.  * Update window.  The update event might be in response to a
  495.  * window resizing.  If so, move and resize the scroll bar,
  496.  * and recalculate the text display.
  497.  *
  498.  * The ValidRect call is done because the HideControl adds the
  499.  * control bounds box to the update region - which would generate
  500.  * another update event!  Since everything is redrawn below anyway,
  501.  * the ValidRect is used to cancel the update.
  502.  */
  503.  
  504. static pascal void
  505. Update (Boolean resized)
  506. {
  507. WindowPtr    w;
  508. DocHandle    doc;
  509. ControlHandle    scroll;
  510. TEHandle    hTE;
  511. Rect    r;
  512.  
  513.     GetPort (&w);
  514.     doc = WindDocHandle (w);
  515.     scroll = DocScroll (doc);
  516.     hTE = DocTE (doc);
  517.  
  518.     if (resized)
  519.     {
  520.         r = w->portRect;
  521.         EraseRect (&r);
  522.         HideControl (scroll);
  523.         r = (**scroll).contrlRect;
  524.         ValidRect (&r);
  525.         CalcScrollRect (w, &r);
  526.         SizeControl (scroll, 16, r.bottom - r.top);
  527.         MoveControl (scroll, r.left, r.top);
  528.         OverhaulDisplay (doc);
  529.         ShowControl (scroll);
  530.     }
  531.     else
  532.     {
  533.         r = (**hTE).viewRect;
  534.         TEUpdate (&r, hTE);        /* redraw text display */
  535.         if (WindowIsActive (w))
  536.             DrawControls (w);    /* redraw scroll bar */
  537.         else
  538.         {
  539.             /* draw outline of scroll, erase interior */
  540.             r = (**scroll).contrlRect;
  541.             FrameRect (&r);
  542.             InsetRect (&r, 1, 1);
  543.             EraseRect (&r);
  544.         }
  545.     }
  546.  
  547.     DrawGrowBox (w);
  548. }
  549.  
  550.  
  551. /*
  552.  * When the window comes active, highlight the scroll bar appropriately.
  553.  * When the window is deactivated, hide the scroll bar (this is drawn
  554.  * immediately rather than invalidating the rectangle and waiting for
  555.  * Update(), because that just seems too slow).
  556.  *
  557.  * Redraw the grow box.
  558.  *
  559.  * Notify the host as appropriate.
  560.  *
  561.  * Note that clicking close box hides the window, which generates a
  562.  * deactivate event, so there is no need for a close notifier.
  563.  */
  564.  
  565. static pascal void
  566. Activate (Boolean active)
  567. {
  568. WindowPtr    w;
  569. DocHandle    doc;
  570. ControlHandle    scroll;
  571. RgnHandle    oldClip;
  572. Rect        r;
  573.  
  574.     GetPort (&w);
  575.     doc = WindDocHandle (w);
  576.     scroll = DocScroll (doc);
  577.  
  578.     DrawGrowBox (w);
  579.     if (active)
  580.     {
  581.         HiliteScroll (doc);
  582.         ShowControl (scroll);
  583.     }
  584.     else
  585.     {
  586.         /* hide scroll but don't show it being hidden */
  587.         oldClip = NewRgn ();
  588.         GetClip (oldClip);
  589.         SetRect (&r, 0, 0, 0, 0);
  590.         ClipRect (&r);
  591.         HideControl (scroll);
  592.         SetClip (oldClip);
  593.         DisposeRgn (oldClip);
  594.         /* now erase inside of scroll (but not outline, to avoid flicker) */
  595.         r = (**scroll).contrlRect;        /* erase scroll */
  596.         InsetRect (&r, 1, 1);                /* but not outline */
  597.         EraseRect (&r);
  598.     }
  599.  
  600.     if (DocActivateProc (doc) != nil)
  601.         (*DocActivateProc (doc)) (active);
  602. }
  603.  
  604.  
  605. /*
  606.  * Clobber a display window.  This routine is written defensively on the
  607.  * assumption that not all pieces of a complete display window are present.
  608.  * This allows it to be called by SkelRmveWind() during window creation
  609.  * attempts if allocations fail.
  610.  *
  611.  * The window's skelWPropDisplayWind property structure will be disposed
  612.  * of by TransSkel, but the data associated with it (returned by WindDocHandle())
  613.  * must be disposed of here.
  614.  *
  615.  * If the window being clobbered is the current output window, do
  616.  * SetDWindow (nil) to turn output off.  Also set dispWind to nil in
  617.  * case the window is the current display window.
  618.  */
  619.  
  620. static pascal void
  621. Clobber (void)
  622. {
  623. WindowPtr    w;
  624. DocHandle    doc;
  625. TEHandle    hTE;
  626.  
  627.     GetPort (&w);
  628.     doc = WindDocHandle (w);
  629.  
  630.     if (w == curDispWind)
  631.         SetDWindow (nil);
  632.  
  633.     /*
  634.      * Toss document record and any pieces that exist
  635.      */
  636.     if (doc != (DocHandle) nil)
  637.     {
  638.         if ((hTE = DocTE (doc)) != (TEHandle) nil)
  639.             TEDispose (hTE);                        /* toss text record */
  640.         DisposeHandle ((Handle) doc);
  641.     }
  642.     DisposeWindow (w);            /* toss window (scroll bar, too) */
  643. }
  644.  
  645.  
  646. /* ---------------------------------------------------------------- */
  647. /*                            Control Routines                        */
  648. /* ---------------------------------------------------------------- */
  649.  
  650.  
  651. /*
  652.  * Test whether a window is a legal display window or not
  653.  */
  654.  
  655. pascal Boolean
  656. IsDWindow (WindowPtr w)
  657. {
  658.     return (WindDocHandle (w) != nil);
  659. }
  660.  
  661.  
  662. /*
  663.  * Return handle to display window's text record
  664.  */
  665.  
  666. pascal TEHandle
  667. GetDWindowTE (WindowPtr w)
  668. {
  669. DocHandle    doc;
  670.  
  671.     return ((doc = WindDocHandle (w)) == nil ? nil : DocTE (doc));
  672. }
  673.  
  674.  
  675. /*
  676.  * Change the text display characteristics of a display window
  677.  * and redisplay it.  As a side effect, this always scrolls to the
  678.  * home position.
  679.  */
  680.  
  681. pascal void
  682. SetDWindowStyle (WindowPtr w, short font, short size, short wrap, short just)
  683. {
  684. DocHandle    doc;
  685. GrafPtr        savePort;
  686. FontInfo    f;
  687. TEHandle    hTE;
  688. Rect        r;
  689.  
  690.     if (w == nil)            /* reset window creation defaults */
  691.     {
  692.         d_font = font;
  693.         d_size = size;
  694.         d_wrap = wrap;
  695.         d_just = just;
  696.         return;
  697.     }
  698.  
  699.     if ((doc = WindDocHandle (w)) != (DocHandle) nil)
  700.     {
  701.         GetPort (&savePort);
  702.         SetPort (w);
  703.         hTE = DocTE (doc);
  704.         r = (**hTE).viewRect;
  705.         EraseRect (&r);
  706.         r = (**hTE).destRect;    /* scroll home without redrawing */
  707.         OffsetRect (&r, 0, 2 - r.top);
  708.         (**hTE).destRect = r;
  709.  
  710.         (**hTE).crOnly = wrap;    /* set word wrap */
  711.         TESetJust (just, hTE);    /* set justification */
  712.  
  713.         TextFont (font);         /* set the font and point size */
  714.         TextSize (size);        /* of text record (this is the */
  715.         GetFontInfo (&f);        /* hard part) */
  716.         (**hTE).lineHeight = f.ascent + f.descent + f.leading;
  717.         (**hTE).fontAscent = f.ascent;
  718.         (**hTE).txFont = font;
  719.         (**hTE).txSize = size;
  720.  
  721.         OverhaulDisplay (doc);
  722.         SetPort (savePort);
  723.     }
  724. }
  725.  
  726.  
  727. /*
  728.  * Scroll the text in the window so that line lineNum is at the top.
  729.  * First line is line zero.
  730.  */
  731.  
  732. pascal void
  733. SetDWindowPos (WindowPtr w, short lineNum)
  734. {
  735. GrafPtr        savePort;
  736. DocHandle    doc;
  737.  
  738.     if ((doc = WindDocHandle (w)) != (DocHandle) nil)
  739.     {
  740.         GetPort (&savePort);
  741.         SetPort (w);
  742.         ScrollText (doc, lineNum - GetCtlValue (DocScroll (doc)));
  743.         SetPort (savePort);
  744.     }
  745. }
  746.  
  747.  
  748. /*
  749.  * Set display window activate notification procedure.
  750.  * Pass nil to disable it.
  751.  */
  752.  
  753. pascal void
  754. SetDWindowNotify (WindowPtr w, TDispActivateProcPtr p)
  755. {
  756. DocHandle    doc;
  757.  
  758.     if (w == nil)            /* reset window creation default */
  759.         d_activate = p;
  760.     else if ((doc = WindDocHandle (w)) != (DocHandle) nil)
  761.         DocActivateProc (doc) = p;
  762. }
  763.  
  764.  
  765. /*
  766.  * Set display window autoflush characteristics
  767.  */
  768.  
  769. pascal void
  770. SetDWindowFlush (WindowPtr w, long maxText, long flushAmt)
  771. {
  772. DocHandle    doc;
  773.  
  774.     if (maxText > 32767L)
  775.         maxText = 32767L;
  776.     if (maxText < d_loMaxText)
  777.         maxText = d_loMaxText;
  778.     if (flushAmt < d_loFlushAmt)
  779.         flushAmt = d_loFlushAmt;
  780.  
  781.     if (w == nil)            /* reset window creation defaults */
  782.     {
  783.         d_maxText = maxText;
  784.         d_flushAmt = flushAmt;
  785.         return;
  786.     }
  787.  
  788.     if ((doc = WindDocHandle (w)) != (DocHandle) nil)
  789.     {
  790.         DocMaxText (doc) = maxText;
  791.         DocFlushAmt (doc) = flushAmt;
  792.     }
  793. }
  794.  
  795.  
  796. /*
  797.  * Set which display window is to be used for output.  If theWind
  798.  * is nil, output is turned off.  If theWind is not a legal display
  799.  * window, nothing is done.
  800.  */
  801.  
  802. pascal void
  803. SetDWindow (WindowPtr w)
  804. {
  805.     if (w == nil || IsDWindow (w))
  806.     {
  807.         curDispWind = w;
  808.     }
  809. }
  810.  
  811.  
  812. /*
  813.  * Get the WindowPtr of the current output display window.  If
  814.  * output is turned off, this will be nil.
  815.  */
  816.  
  817. pascal WindowPtr
  818. GetDWindow (void)
  819. {
  820.     return (curDispWind);
  821. }
  822.  
  823.  
  824. /*
  825.  * Flush text from the window and readjust the display.
  826.  */
  827.  
  828. pascal void
  829. FlushDWindow (WindowPtr w, long byteCount)
  830. {
  831. DocHandle    doc;
  832. TEHandle    hTE;
  833.  
  834.     if ((doc = WindDocHandle (w)) != (DocHandle) nil)
  835.     {
  836.         hTE = DocTE (doc);
  837.         TESetSelect (0L, byteCount, hTE);    /* select text */
  838.         TEDelete (hTE);                        /* clobber it */
  839.         OverhaulDisplay (doc);
  840.     }
  841. }
  842.  
  843.  
  844. /*
  845.  * Create and initialize a display window and the associated data
  846.  * structures.  If the window and data cannot be allocated, destroy
  847.  * the window and return nil.  Otherwise return the window.
  848.  *
  849.  * The window is made the current output window, but the caller should
  850.  * set and restore the port before and after calling SetupDocWind().
  851.  */
  852.  
  853. static WindowPtr
  854. SetupDocWind (WindowPtr w)
  855. {
  856. Rect    r;
  857. DocHandle    doc;
  858. SkelWindPropHandle    prop;
  859. ControlHandle    scroll;
  860. TEHandle        hTE;
  861.  
  862.     if (!SkelWindow (w,    /* the window */
  863.                 Mouse,            /* mouse click handler */
  864.                 nil,            /* key clicks are ignored */
  865.                 Update,            /* window updating procedure */
  866.                 Activate,        /* window activate/deactivate procedure */
  867.                 nil,            /* TransSkel hides window if no close proc */
  868.                                 /* (generates deactivate event) */
  869.                 Clobber,        /* window disposal procedure */
  870.                 nil,            /* no idle proc */
  871.                 false))            /* irrelevant since no idle proc */
  872.     {
  873.         DisposeWindow (w);
  874.         return (nil);
  875.     }
  876.  
  877.     /*
  878.      * After this point SkelRmveWind() can be called to remove the window
  879.      * if any allocations fail.
  880.      */
  881.  
  882.     /*
  883.      * Get new document record, attach to window property list.
  884.      * Also make document record point to window.
  885.      */
  886.  
  887.     if (!SkelAddWindProp (w, skelWPropDisplayWind, (long) 0L))
  888.     {
  889.         SkelRmveWind (w);
  890.         return (nil);
  891.     }
  892.     doc = New (DocRecord);
  893.     if (doc == (DocHandle) nil)
  894.     {
  895.         SkelRmveWind (w);
  896.         return (nil);
  897.     }
  898.     prop = SkelGetWindProp (w, skelWPropDisplayWind);
  899.     (**prop).skelWPropData = (long) doc;
  900.     DocWind (doc) = w;
  901.  
  902.     /*
  903.      * Build the scroll bar.  Make sure the borders overlap the
  904.      * window frame and the frame of the grow box.
  905.      */
  906.  
  907.     CalcScrollRect (w, &r);
  908.     scroll = NewControl (w, &r, "\p", true, 0, 0, 0, scrollBarProc, 0L);
  909.     DocScroll (doc) = scroll;
  910.  
  911.     /*
  912.      * Create the TE record used for text display.  Use defaults for
  913.      * display characteristics.  Setting window style overhauls
  914.      * display, so can cancel any update event pending for the window.
  915.      */
  916.  
  917.     CalcEditRect (w, &r);
  918.     hTE = TENew (&r, &r);
  919.     DocTE (doc) = hTE;
  920.  
  921.     if (scroll == (ControlHandle) nil || hTE == (TEHandle) nil)
  922.     {
  923.         SkelRmveWind (w);
  924.         return (nil);
  925.     }
  926.  
  927.     SetDWindowNotify (w, d_activate);
  928.     SetDWindowFlush (w, d_maxText, d_flushAmt);
  929.     SetDWindowStyle (w, d_font, d_size, d_wrap, d_just);
  930.  
  931.     /*
  932.      * Make window current display output window
  933.      */
  934.  
  935.     SetDWindow (w);
  936.     return (w);
  937. }
  938.  
  939.  
  940. /*
  941.  * Create and initialize a display window and the associated data
  942.  * structures, and return the window pointer.
  943.  *
  944.  * The parameters are similar to those for NewWindow.  See Inside
  945.  * Macintosh.
  946.  *
  947.  * Preserves the current port.  If the window is visible,
  948.  * an activate event will follow, at which point the port
  949.  * will be set to the window.
  950.  */
  951.  
  952. pascal WindowPtr
  953. NewDWindow (Rect *bounds, StringPtr title, Boolean visible,
  954.                     WindowPtr behind, Boolean goAway, long refCon)
  955. {
  956. WindowPtr    w;
  957. GrafPtr        savePort;
  958.  
  959.     if (SkelQuery (skelQHasColorQD))
  960.     {
  961.         w = NewCWindow (nil,
  962.                            bounds,
  963.                            title,
  964.                            visible,
  965.                            documentProc + 8,
  966.                            behind,
  967.                            goAway,
  968.                            refCon);
  969.     }
  970.     else
  971.     {
  972.         w = NewWindow (nil,
  973.                            bounds,
  974.                            title,
  975.                            visible,
  976.                            documentProc + 8,
  977.                            behind,
  978.                            goAway,
  979.                            refCon);
  980.     }
  981.  
  982.     if (w != (WindowPtr) nil)
  983.     {
  984.         GetPort (&savePort);
  985.         w = SetupDocWind (w);        /* nil if allocation failed */
  986.         SetPort (savePort);
  987.     }
  988.     return (w);
  989. }
  990.  
  991.  
  992. /*
  993.  * Create and initialize a display window (using a resource) and
  994.  * the associated data structures, and return the window pointer.
  995.  * Install window in list of display windows.  In single-window
  996.  * mode, disallow creation of a new window if one already exists.
  997.  *
  998.  * The parameters are similar to those for GetNewWindow.  See Inside
  999.  * Macintosh.
  1000.  */
  1001.  
  1002. pascal WindowPtr
  1003. GetNewDWindow (short resourceNum, WindowPtr behind)
  1004. {
  1005. WindowPtr    w;
  1006. GrafPtr        savePort;
  1007.  
  1008.     if (SkelQuery (skelQHasColorQD))
  1009.         w = GetNewCWindow (resourceNum, nil, behind);
  1010.     else
  1011.         w = GetNewWindow (resourceNum, nil, behind);
  1012.  
  1013.     if (w != (WindowPtr) nil)
  1014.     {
  1015.         GetPort (&savePort);
  1016.         w = SetupDocWind (w);        /* nil if allocation failed */
  1017.         SetPort (savePort);
  1018.     }
  1019.     return (w);
  1020. }
  1021.  
  1022.  
  1023. /* ------------------------------------------------------------ */
  1024. /*                        Output Routines                            */
  1025. /* ------------------------------------------------------------ */
  1026.  
  1027.  
  1028. /*
  1029.  * Write text to display area if output is on (curDispWind != nil).
  1030.  * DisplayText is the fundamental output routine.  All other
  1031.  * output calls map (eventually) to it.
  1032.  *
  1033.  * First check whether the insertion will cause overflow and flush
  1034.  * out some stuff if so.  Insert new text at the end, then test
  1035.  * whether lines must be scrolled to get the new stuff to show up.
  1036.  * If yes, then do the scroll.  Set values of scroll bar properly
  1037.  * and highlight as appropriate.
  1038.  *
  1039.  * The current port is preserved.  Since all output calls end up
  1040.  * here, it's the only output routine that has to save the port
  1041.  * and check whether output is on.
  1042.  */
  1043.  
  1044. pascal void
  1045. DisplayText (Ptr theText, long len)
  1046. {
  1047. DocHandle    doc;
  1048. TEHandle    hTE;
  1049. ControlHandle    scroll;
  1050. short    nLines;            /* # of lines in TERec */
  1051. short    dispLines;        /* # of lines displayable in window */
  1052. short    topLines;        /* # of lines currently scrolled off top */
  1053. short    scrollLines;    /* # of lines to scroll up */
  1054. short    lHeight;
  1055. Rect    r;
  1056. GrafPtr    savePort;
  1057.  
  1058.     if (curDispWind == nil)
  1059.         return;
  1060.  
  1061.     GetPort (&savePort);
  1062.     SetPort (curDispWind);
  1063.     doc = WindDocHandle (curDispWind);
  1064.     hTE = DocTE (doc);
  1065.     scroll = DocScroll (doc);
  1066.  
  1067.     if ((**hTE).teLength + len > DocMaxText (doc))    /* check overflow */
  1068.     {
  1069.         FlushDWindow (curDispWind, DocFlushAmt (doc));
  1070.         DisplayString ((StringPtr) "\p\r(autoflush occurred)\r");
  1071.     }
  1072.  
  1073.     lHeight = (**hTE).lineHeight;
  1074.     TESetSelect (32767L, 32767L, hTE);    /* set to insert at end */
  1075.     TEInsert (theText, len, hTE);
  1076.     r = (**hTE).viewRect;
  1077.     nLines = (**hTE).nLines;
  1078.     dispLines = (r.bottom - r.top) / lHeight;
  1079.     topLines = LinesOffTop (hTE);
  1080.     scrollLines = nLines - (topLines + dispLines);
  1081.     if (scrollLines > 0) /* must scroll up */
  1082.         TEScroll (0, -lHeight * scrollLines, hTE); /* scroll up */
  1083.     topLines = nLines - dispLines;
  1084.     if (topLines >= 0 && GetCtlMax (scroll) != topLines)
  1085.     {
  1086.         SetCtlMax (scroll, topLines);
  1087.         SetCtlValue (scroll, topLines);
  1088.     }
  1089.     HiliteScroll (doc);
  1090.     SetPort (savePort);
  1091. }
  1092.  
  1093.  
  1094. /*
  1095.  * Derived output routines:
  1096.  *
  1097.  * DisplayString    Write (Pascal) string
  1098.  *
  1099.  * DisplayLong        Write value of long integer
  1100.  * DisplayShort        Write value of short integer
  1101.  * DisplayChar        Write character
  1102.  *
  1103.  * DisplayHexLong    Write value of long integer in hex (8 digits)
  1104.  * DisplayHexShort    Write value of short integer in hex (4 digits)
  1105.  * DisplayHexChar    Write value of character in hex (2 digit)
  1106.  *
  1107.  * DisplayOSType    Write OSType value
  1108.  *
  1109.  * DisplayBoolean    Write boolean value
  1110.  * DisplayLn        Write carriage return
  1111.  */
  1112.  
  1113. pascal void
  1114. DisplayString (StringPtr str)
  1115. {
  1116.     DisplayText ((Ptr) (str+1), (long) str[0]);
  1117. }
  1118.  
  1119.  
  1120. pascal void
  1121. DisplayCString (char *str)
  1122. {
  1123. long    len = 0;
  1124. char    *s;
  1125.  
  1126.     for (s = str; *s != '\0'; s++)
  1127.         ++len;
  1128.     DisplayText ((Ptr) str, len);
  1129. }
  1130.  
  1131.  
  1132. pascal void
  1133. DisplayChar (short c)
  1134. {
  1135. char    ch = c;
  1136.  
  1137.     DisplayText (&ch, 1L);
  1138. }
  1139.  
  1140.  
  1141. pascal void
  1142. DisplayShort (short i)
  1143. {
  1144.     DisplayLong ((long) i);
  1145. }
  1146.  
  1147.  
  1148. pascal void
  1149. DisplayLong (long l)
  1150. {
  1151. Str255        s;
  1152.  
  1153.     NumToString (l, s);
  1154.     DisplayString (s);
  1155. }
  1156.  
  1157.  
  1158. pascal void
  1159. DisplayLn (void)
  1160. {
  1161.     DisplayChar ('\r');
  1162. }
  1163.  
  1164.  
  1165. pascal void
  1166. DisplayBoolean (Boolean b)
  1167. {
  1168.     DisplayString (b ? (StringPtr) "\ptrue" : (StringPtr) "\pfalse");
  1169. }
  1170.  
  1171.  
  1172. static char
  1173. HexByte (short value)    /* should be 0..15 */
  1174. {
  1175.     DisplayChar ((char) (value + (value < 10 ? '0' : 'a' - 10)));
  1176. }
  1177.  
  1178.  
  1179. pascal void
  1180. DisplayHexChar (short c)
  1181. {
  1182.     HexByte ((short) (c >> 4) & 0x0f);
  1183.     HexByte ((short) c & 0x0f);
  1184. }
  1185.  
  1186.  
  1187. pascal void
  1188. DisplayHexShort (short i)
  1189. {
  1190.     DisplayHexChar ((char) ((i >> 8) & 0xff));
  1191.     DisplayHexChar ((char) (i & 0xff));
  1192. }
  1193.  
  1194.  
  1195. pascal void
  1196. DisplayHexLong (long l)
  1197. {
  1198.     DisplayHexShort ((short) (l >> 16) & 0xffff);
  1199.     DisplayHexShort ((short) l & 0xffff);
  1200. }
  1201.  
  1202.  
  1203. pascal void
  1204. DisplayOSType (OSType type)
  1205. {
  1206. long    l = (long) type;
  1207.  
  1208.     DisplayChar ((l >> 24) & 0xff);
  1209.     DisplayChar ((l >> 16) & 0xff);
  1210.     DisplayChar ((l >> 8) & 0xff);
  1211.     DisplayChar (l & 0xff);
  1212. }
  1213.